#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <sys/epoll.h>
#include <errno.h>
#include "Socket.hpp"
#include "Logger.hpp"
#include "InetAddr.hpp"
#include <unistd.h>



class EpollServer
{
    inline static const int epoll_default_size = 64;//本身是框定epoll红黑树大小的数字，但是现在已被忽略
    inline static const uint32_t epoll_default_events = EPOLLIN;

    private:

    void EpollAdd(int fd,uint32_t event)
    {
        struct epoll_event sock;
        sock.events = event;
        sock.data.fd = fd;
        if(epoll_ctl(_epfd,EPOLL_CTL_ADD,fd,&sock) != 0)
        {
            LOG(LogLevel::ERROR) << "epoll_add error";
            exit(errno);
        }
    }

    void EpollMod(int fd,uint32_t event)
    {
        struct epoll_event sock;
        sock.events = event;
        sock.data.fd = fd;
        if(epoll_ctl(_epfd,EPOLL_CTL_MOD,fd,&sock) != 0)
        {
            LOG(LogLevel::ERROR) << "epoll_mod error";
            exit(errno);
        }
    }

    void EpollDel(int fd)
    {
        if(epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,nullptr) != 0)
        {
            LOG(LogLevel::ERROR) << "epoll_del error";
            exit(errno);
        }
    }
    public:
    EpollServer(uint16_t port = 8080):_listensock(std::make_unique<TcpSocket>()),_helper_arr(epoll_default_size)
    {
        //RAII风格
        _listensock->BuildListenSocketMethod(port);
        _epfd = epoll_create(epoll_default_size);
        if(_epfd < 0)
        {
            LOG(LogLevel::ERROR) << "epoll_create error";
            exit(errno);
        }
        EpollAdd(_listensock->SockFd(),epoll_default_events);
    }


    void Accept(int listensock_fd)
    {
        InetAddr client;
        socklen_t len = client.Len();
        int fd = accept(listensock_fd,(struct sockaddr*)&client.Addr(),&len);
        if(fd < 0)
            LOG(LogLevel::ERROR) << "accept error";
        else
        {
            LOG(LogLevel::INFO) << "accept success";
            EpollAdd(fd,epoll_default_events);
        }
    }
    
    void Recv(int fd)
    {
        int buffer[1024] = {0};
        int n = recv(fd,buffer,sizeof(buffer) - 1,0);//等待不再由recv完成
        if(n > 0)
        {
            LOG(LogLevel::INFO) << "recv success";
            buffer[n] = 0;
            send(fd,buffer,n,0);
        }
        else if(n == 0)
        {
            LOG(LogLevel::INFO) << "client quit";
            EpollDel(fd);
            close(fd);
        }
        else
        {
            LOG(LogLevel::ERROR) << "recv error";
        }
    }
    void EventDispatch(int nfds)
    {
        for(int i = 0;i < nfds;i++)
        {
            //都是已经就绪的
            int fd = _helper_arr[i].data.fd;
            uint32_t events = _helper_arr[i].events;
            if((fd == _listensock->SockFd()) && (events & EPOLLIN))
                Accept(fd);
            else if(events & EPOLLIN)
                Recv(fd);       
        }
    }
    void Run()
    {
        while(true)
        {
            int n = epoll_wait(_epfd,&_helper_arr[0],_helper_arr.size(),-1);
            if(n > 0)
            {
                LOG(LogLevel::INFO) << "epoll_wait success";
                //进行任务派发
                EventDispatch(n);
            }
            else if(n == 0)
            {
                LOG(LogLevel::INFO) << "eoll timeout";
                continue;
            }
            else 
            {
                //如果被信号中断了，那么重来一次
                if(errno == EINTR)
                    continue;                
                else
                {
                    LOG(LogLevel::ERROR) << "epoll error";
                    close(_epfd);//注意相应文件描述符需要被关闭
                    exit(errno); 
                }
            }
        }
    }

    

    ~EpollServer()
    {}
private:
    std::unique_ptr<Socket> _listensock;
    int _epfd;//管理整个epoll
    std::vector<struct epoll_event> _helper_arr;//对应底层的就绪队列
};
